<?php

function createNonceStr($length = 16)
{
    $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    $str = "";
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}

function ToUrlParams($params)
{
    $string = '';
    ksort($params);
    if (!empty($params)) {
        $array = array();
        foreach ($params as $key => $value) {
            $array[] = $key . '=' . $value;
        }
        $string = implode("&", $array);
    }
    return $string;
}

function get_millisecond()
{
    list($usec, $sec) = explode(" ", microtime());
    $msec = round($usec * 1000);
    return str_pad($msec, 3, '0', STR_PAD_RIGHT);
}

function getLatLong($address, $ak = '87c3e9435d10e6ad8a06622506836849')
{
    $location = null;
    if (!$address) return $location;
    $url = "http://api.map.baidu.com/geocoder/v2/?output=json&ak=$ak&address=" . $address;
    $response = get_url_content($url);
    $response = json_decode($response);
    if (!$response) return $location;
    if ($response->status == 0)
        $location = $response->result->location;
    return $location;
}

function getLocation($lng, $lat, $ak = '87c3e9435d10e6ad8a06622506836849')
{
    $address = "";
    if ($lng < 100) return "";
    $url = "http://api.map.baidu.com/geocoder/v2/?ak=$ak&output=json&location=$lat,$lng";
    $response = get_url_content($url);
    $response = json_decode($response);
    if (!$response) return $address;
    if ($response->status == 0) {
        $province = $response->result->addressComponent->province;
        $city = $response->result->addressComponent->city;
        $district = $response->result->addressComponent->district;
        $sematic_description = $response->result->sematic_description;
        if ($sematic_description)
            $address = $province . $city . $district . $sematic_description;
        else
            $address = $response->result->formatted_address;
    }
    return $address;
}

/**
 * 将数组转换成树
 * @param array $sourceArr 要转换的数组
 * @param string $key 数组中确认父子的key，例子中为“id”
 * @param string $parentKey 数组中父key，例子中为“parentId”
 * @param type $childrenKey 要在树节点上索引子节点的key，例子中为“children”
 * @return array 返回生成的树
 */
function arrayToTree($sourceArr, $key, $parentKey, $childrenKey)
{
    $tempSrcArr = array();

    $allRoot = TRUE;
    foreach ($sourceArr as $v) {
        $isLeaf = TRUE;
        foreach ($sourceArr as $cv) {
            if (($v[$key]) != $cv[$key]) {
                if ($v[$key] == $cv[$parentKey]) {
                    $isLeaf = FALSE;
                }
                if ($v[$parentKey] == $cv[$key]) {
                    $allRoot = FALSE;
                }
            }
        }
        if ($isLeaf) {
            $leafArr[$v[$key]] = $v;
        }
        $tempSrcArr[$v[$key]] = $v;
    }
    if ($allRoot) {
        return $tempSrcArr;
    } else {
        unset($v, $cv, $sourceArr, $isLeaf);
        foreach ($leafArr as $v) {
            if (isset($tempSrcArr[$v[$parentKey]])) {
                $tempSrcArr[$v[$parentKey]][$childrenKey] = (isset($tempSrcArr[$v[$parentKey]][$childrenKey]) && is_array($tempSrcArr[$v[$parentKey]][$childrenKey])) ? $tempSrcArr[$v[$parentKey]][$childrenKey] : array();
                array_push($tempSrcArr[$v[$parentKey]][$childrenKey], $v);
                unset($tempSrcArr[$v[$key]]);
            }
        }
        unset($v);
        return arrayToTree($tempSrcArr, $key, $parentKey, $childrenKey);
    }
}

function getTree($data, $pid = 0, $key = 'id', $pKey = 'parentId', $childKey = 'child', $maxDepth = 0)
{
    static $depth = 0;
    $tree = array();
    $depth++;
    if (intval($maxDepth) <= 0) {
        $maxDepth = count($data) * count($data);
    }
    if ($depth > $maxDepth) {
        return $tree;
    }

    foreach ($data as $rk => $rv) {
        if ($rv[$pKey] == $pid) {
            $rv[$childKey] = getTree($data, $rv[$key], $key, $pKey, $childKey, $maxDepth);
            $tree[] = $rv;
        }
    }
    return $tree;
}

/*** 根据两点间经纬度坐标（double值），计算两点间距离，单位为米 */
function getDistance($lng1, $lat1, $lng2, $lat2)
{
    $earthRadius = 6367000;
    if (strstr($lng1, '.') == 0) {
        $lng1 = substr($lng1, 0, 3) . "." . substr($lng1, 3, 6);
        $lat1 = substr($lat1, 0, 2) . "." . substr($lat1, 2, 6);
        $lng2 = substr($lng2, 0, 3) . "." . substr($lng2, 3, 6);
        $lat2 = substr($lat2, 0, 2) . "." . substr($lat2, 2, 6);
    }
    $lat1 = ($lat1 * pi()) / 180;
    $lng1 = ($lng1 * pi()) / 180;

    $lat2 = ($lat2 * pi()) / 180;
    $lng2 = ($lng2 * pi()) / 180;

    $calcLong = $lng2 - $lng1;
    $calcLat = $lat2 - $lat1;
    $stepOne = pow(sin($calcLat / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLong / 2), 2);
    $stepTwo = 2 * asin(min(1, sqrt($stepOne)));
    $Distance = $earthRadius * $stepTwo;
    return round($Distance) / 1000;
}

/**
 * @param lat 纬度 lon 经度 raidus 单位米
 * return minLat,minLng,maxLat,maxLng
 */
function getAround($lon, $lat, $raidus)
{
    $PI = 3.14159265;
    $itude = array();
    $degree = (24901 * 1609) / 360.0;
    $raidusMile = $raidus * 1000;

    $dpmLat = 1 / $degree;
    $radiusLat = $dpmLat * $raidusMile;
    $itude['lat'][] = ($lat - $radiusLat);
    $itude['lat'][] = ($lat + $radiusLat);

    $mpdLng = $degree * cos($lat * ($PI / 180));
    $dpmLng = 1 / $mpdLng;
    $radiusLng = $dpmLng * $raidusMile;
    $itude['lng'][] = ($lon - $radiusLng);
    $itude['lng'][] = ($lon + $radiusLng);
    return $itude;
}

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0)
{
    // 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
    $ckey_length = 4;

    // 密匙
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);

    // 密匙a会参与加解密
    $keya = md5(substr($key, 0, 16));
    // 密匙b会用来做数据完整性验证
    $keyb = md5(substr($key, 16, 16));
    // 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) :
        substr(md5(microtime()), -$ckey_length)) : '';
    // 参与运算的密匙
    $cryptkey = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);
    // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，
    //解密时会通过这个密匙验证数据完整性
    // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :
        sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    // 产生密匙簿
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    // 核心加解密部分
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        // 从密匙簿得出密匙进行异或，再转成字符
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'DECODE') {
        // 验证数据有效性，请看未加密明文的格式
        if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&
            substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)
        ) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        // 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
        // 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}

//    参数加密
function encryption_param($data, $str = 'sltx112')
{
    ksort($data);
    $wait = "";
    foreach ($data as $key => $val) {
        $wait .= $key . '=' . $val . '&';
    }
    $wait = substr($wait, 0, -1);
    $sign = authcode($wait, 'ENCODE', $str);
    return $sign;
}

//  参数解密 返回 数组
function decrypt_param($sign, $str = 'sltx112')
{
    $sign_decode = authcode($sign, 'DECODE', $str);
    $arrays = explode('&', $sign_decode);
    $param = array();
    foreach ($arrays as $array) {
        $e = explode('=', $array);
        if (isset($e[1]) && isset($e[0])) $param[$e[0]] = $e[1];
    }
    return $param;
}

//判断是否为日期格式
function isdate($time)
{
    $isdate = preg_match("/^[0-9]{4}(\-|\/)[0-9]{1,2}(\\1)[0-9]{1,2}(|\s+[0-9]{1,2}(|:[0-9]{1,2}(|:[0-9]{1,2})))$/", $time);
    return $isdate;
}

/*
 * day1 时间小
 * day2 时间大
 * 如果填反 两个时间间隔天数返回 0天
 */
function diffBetweenTwoDays($day1, $day2)
{
    $endtime = strtotime($day2); //时间大
    $starttime = strtotime($day1); //时间小
    $day_arr = array();
    while (($starttime = strtotime('+1 day', $starttime)) <= $endtime) {
        $day_arr[] = date('Y-m-d', $starttime); // 取得递增天;
    }
    $day_num = count($day_arr);
    return $day_num;
}

//判断是否有中文字符
function isChinesecharacters($str)
{
}

function SHA256Hex($str)
{
    $re = hash('sha256', $str, true);
    return bin2hex($re);
}

if (!function_exists('bcrypt')) {
    /**
     * Hash the given value.
     *
     * @param string $value
     * @param array $options
     * @return string
     */
    function bcrypt($value, $options = [])
    {
        return app('hash')->make($value, $options);
    }
}
if (!function_exists('getStrLen')) {
    /**
     * string the given value.
     *
     * @param string $value
     * @return string
     */
    function getStrLen($value)
    {
        $j = 0;
        for ($i = 0; $i < mb_strlen($value); $i++) {
            if (ord(mb_substr($value, $i, 1)) > 0xa0) {
                $j++;
            }
        }
        return $j;
    }
}

/**
 * @brief 获取网站根路径
 * @param string $protocol 协议  默认为http协议，不需要带'://'
 * @return String $baseUrl  网站根路径
 *
 */
function getHost()
{
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    $host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '');
    $baseUrl = $protocol . $host . '/';

    return $baseUrl;
}

/**
 * 把键值对字符串分割成数组
 * @param $str
 * @param string $delimiter
 * @return array
 */
function strToKeyValArr($str, $delimiter = ';')
{
    $result = array();
    $arr = explode($delimiter, $str);

    foreach ($arr as $item) {
        $data = explode(':', trim($item));
        if (count($data) == 2) {
            $result[$data[0]] = $data[1];
        }
    }

    return $result;
}

/**
 * 名称加密
 * @param array $data
 * @param array $fields
 *
 * @return array
 */
function mask_name(array &$data, array $fields, $mask_all = FALSE)
{
    foreach ($fields as $path)
    {
        $value = data_get($data, $path);
        $len   = mb_strlen($value);
        if (is_string($value) && $len)
        {
            if ($mask_all)
            {
                $masked = str_repeat('*', $len);
            }
            else
            {
                $masked = mb_substr($value, 0, 1) . str_repeat('*', $len - 1);
            }
            data_set($data, $path, $masked);
        }
    }

    return $data;
}

/**
 * 电话加密
 * @param array $data
 * @param array $fields
 *
 * @return array
 */
function mask_telephone(array &$data, $fields, $mask_all = FALSE)
{
    foreach ($fields as $path)
    {
        $value = data_get($data, $path);
        if (is_string($value))
        {
            if ($mask_all)
            {
                $masked = str_repeat('*', mb_strlen($value));
            }
            elseif (preg_match('/^([0-9]{3,4}-)?[0-9]{7,8}$/', $value))
            {
                $masked = substr_replace($value, "****",-6,4);
            }
            else
            {
                $masked = preg_replace('/(?=\d{11})(\d{3})\d{5}(\d{3})/m', '$1*****$2', $value);
            }

            data_set($data, $path, $masked);
        }
    }

    return $data;
}

/**
 * 将时间转化为多久前
 */
function ChangeTime($time)
{
    $time = time() - $time;
    if(is_numeric($time)){  
        $value = array(  
              "years" => 0, "days" => 0, "hours" => 0,  
              "minutes" => 0, "seconds" => 0,  
        );  
        if($time >= 31556926){  
              $value["years"] = floor($time/31556926);  
              $time = ($time%31556926);
              $t = $value["years"].'年前';  
        }  
        elseif(31556926 >$time && $time >= 86400){  
             $value["days"] = floor($time/86400);  
              $time = ($time%86400);
              $t = $value["days"].'天前';  
        }  
        elseif(86400 > $time && $time >= 3600){  
             $value["hours"] = floor($time/3600);  
              $time = ($time%3600);
              $t = $value["hours"].'小时前';  
        }  
        elseif(3600 > $time && $time >= 60){  
              $value["minutes"] = floor($time/60);  
              $time = ($time%60);
              $t = $value["minutes"].'分钟前';  
        }else{
            $t = $time.'秒前';
        }   
        return $t;    
    }else{  
        return date('Y-m-d H:i:s',time());  
    }  
}

/**
 * 将时间转为时间差
 */
function timestampToDH($timestamp) 
{
    $diff = time() - $timestamp; // 计算当前时间与目标时间戳的差值（秒）
    $timediff = abs($diff); // 处理未来时间的负数情况
    $days = intval( $timediff / 86400 );
    $remain = $timediff % 86400;
    if($days){
        $str = $days.'天';
    }
    $hours = intval( $remain / 3600 );
    $remain = $remain % 3600;
    if($hours){
        $str .= $hours.'小时';
    }
    $mins = intval( $remain / 60 );
    if($mins){
        $str .= $mins.'分';
    }
    //$secs = $remain % 60;
    return $str;
}